package com.livepan.server.service.impl;

//import com.github.javaparser.metamodel.LiteralExprMetaModel;

import com.alibaba.fastjson.JSON;
import com.livepan.server.dao.*;
import com.livepan.server.dataobject.*;
import com.livepan.server.error.BusinessException;
import com.livepan.server.error.EmBusinessError;
import com.livepan.server.service.UserService;
import com.livepan.server.service.model.UserModel;
import com.livepan.server.validator.ValidationResult;
import com.livepan.server.validator.ValidatorImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;

import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private ResourceDOMapper resourceDOMapper;

    @Autowired
    RoleResourceDOMapper roleResourceDOMapper;

    @Autowired
    private RoleUserDOMapper roleUserDOMapper;

    @Autowired
    private UserDOMapper userDOMapper;

    @Autowired
    private UserPasswordDOMapper userPasswordDOMapper;

    @Autowired
    private ValidatorImpl validator;

    @Autowired
    private LoginRecordDOMapper loginRecordDOMapper;

    @Override
    public UserModel getUserById(String id) {
        UserDO userDO = userDOMapper.selectByPrimaryKey(id);
        if (userDO == null) {
            return null;
        }
        UserPasswordDO userPasswordDO = getUserPasswordDO(userDO.getId());
        UserModel userModel = convertFromDataObject(userDO, userPasswordDO);
        Map<String, List<String>> resourceMap = getResourceMap(userModel.getId());
        userModel.setPageList(resourceMap.get("pageList"));
        userModel.setRequestList(resourceMap.get("requestList"));
        return userModel;
    }

    @Override
    public UserModel getUserByTelePhone(String telephone) throws BusinessException {
        UserDO userDO = userDOMapper.selectByTelephone(telephone);
        if (userDO == null) {
            return null;
        }
        return convertFromDataObject(userDO, getUserPasswordDO(userDO.getId()));
    }

    @Override
    public void register(UserModel userModel, String ip) throws BusinessException {
        if (userModel == null) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR);
        }

        ValidationResult result = validator.validate(userModel);
        if (result.isHasError()) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, result.getErrMsg());
        }

        //保存用户信息，生成用户的userID
        UserDO userDO = convertFromUserModel(userModel);
        try {
            userDOMapper.insertSelective(userDO);
        } catch (DuplicateKeyException ex) {
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "手机号重复注册");
        }


        //设置密码表的userID为生成的id
        userModel.setId(userDO.getId());

        //保存用户密码信息
        UserPasswordDO userPasswordDO = convertPasswordFromUserModel(userModel);
        userPasswordDOMapper.insertSelective(userPasswordDO);

        LoginRecordDO loginRecordDO = new LoginRecordDO();
        loginRecordDO.setUserId(userDO.getId());
        loginRecordDO.setIsLogin(Byte.parseByte("3"));
        loginRecordDO.setMillisecond(System.currentTimeMillis());
        //todo ip还没有解决问题
        loginRecordDO.setIp(ip);
        loginRecordDOMapper.insertSelective(loginRecordDO);
    }

    @Override
    public UserModel validateLogin(String telephone, String encrptPassword, String ip) throws BusinessException {
        //通过用户的手机获取用户信息

        UserDO userDO = userDOMapper.selectByTelephone(telephone);
        if (userDO == null) {
            throw new BusinessException(EmBusinessError.USER_LOGIN_FAILED);
        }
        UserPasswordDO userPasswordDO = getUserPasswordDO(userDO.getId());
        UserModel userModel = convertFromDataObject(userDO, userPasswordDO);

        if (!StringUtils.equals(encrptPassword, userModel.getEncrptPassword())) {
            throw new BusinessException(EmBusinessError.USER_LOGIN_FAILED);
        }

        LoginRecordDO loginRecordDO = new LoginRecordDO();
        loginRecordDO.setUserId(userDO.getId());
        loginRecordDO.setIsLogin(Byte.parseByte("1"));
        loginRecordDO.setMillisecond(System.currentTimeMillis());
        //todo ip还没有解决问题
        loginRecordDO.setIp(ip);
        loginRecordDOMapper.insertSelective(loginRecordDO);

        return userModel;

    }

    @Override
    public List<Integer> getAllUserId() {
        return userDOMapper.getAllUserId();
    }

    @Override
    public UserModel setEmail(String email, String userId) throws BusinessException {
        UserDO userDO = userDOMapper.selectByPrimaryKey(userId);
        userDO.setEmail(email);
        int count = userDOMapper.updateByPrimaryKey(userDO);
        if (count > 0) {
            return getUserById(userId);
        } else {
            throw new BusinessException(EmBusinessError.USER_INFO_UPDATE_ERROR);
        }
    }

    @Override
    public UserModel setAvatar(String avatarUrl, String userId) throws BusinessException {
        UserDO userDO = userDOMapper.selectByPrimaryKey(userId);
        userDO.setAvatar(avatarUrl);
        int count = userDOMapper.updateByPrimaryKey(userDO);
        if (count > 0) {
            return getUserById(userId);
        } else {
            throw new BusinessException(EmBusinessError.USER_INFO_UPDATE_ERROR, "头像设置错误");
        }
    }

    @Override
    public void logout(String userId, String ip) {
        LoginRecordDO loginRecordDO = new LoginRecordDO();
        loginRecordDO.setUserId(userId);
        loginRecordDO.setIsLogin(Byte.parseByte("2"));
        loginRecordDO.setMillisecond(System.currentTimeMillis());
        //todo ip还没有解决问题
        loginRecordDO.setIp(ip);
        loginRecordDOMapper.insertSelective(loginRecordDO);
    }

    @Override
    public List<Long> getUserLoginRecordList(String userId, Integer recordType) {
        List<LoginRecordDO> loginRecordDOList = loginRecordDOMapper.selectByUserId(userId, recordType);
        List<Long> loginTimeList = new ArrayList<>();
        for (LoginRecordDO loginRecordDO : loginRecordDOList) {
            loginTimeList.add(loginRecordDO.getMillisecond());
        }
        return loginTimeList;
    }

    @Override
    public UserModel updateUserInfo(@NotNull UserModel userModel) {
        UserDO userDO = convertFromUserModel(userModel);
        userDOMapper.updateByPrimaryKey(userDO);
        return getUserById(userModel.getId());
    }

    @Override
    public List<UserModel> getUserList() {
        List<UserDO> userDOList = userDOMapper.getAllUser();
        List<UserModel> userModelList = userDOList.stream().map((item) -> {
            return this.convertFromDataObject(item, null);
        }).collect(Collectors.toList());
        return userModelList;
    }

    private UserDO convertFromUserModel(UserModel userModel) {
        if (userModel == null) {
            return null;
        }

        UserDO userDO = new UserDO();
        BeanUtils.copyProperties(userModel, userDO);
        return userDO;
    }


    private UserPasswordDO convertPasswordFromUserModel(UserModel userModel) {
        if (userModel == null) {
            return null;
        }

        UserPasswordDO userPasswordDO = new UserPasswordDO();
        userPasswordDO.setEncrptPassword(userModel.getEncrptPassword());
        userPasswordDO.setUserId(userModel.getId());
        return userPasswordDO;
    }

    private UserModel convertFromDataObject(UserDO userDO, UserPasswordDO userPasswordDO) {
        if (userDO == null) {
            return null;
        }
        UserModel userModel = new UserModel();
        BeanUtils.copyProperties(userDO, userModel);
        if (userPasswordDO != null) {
            userModel.setEncrptPassword(userPasswordDO.getEncrptPassword());
        }

        return userModel;
    }

    @Override
    public Map<String, List<String>> getResourceMap(String userId) {
        //1. 先得到用户的角色
        RoleUserDOExample roleUserDOExample = new RoleUserDOExample();
        RoleUserDOExample.Criteria criteria = roleUserDOExample.createCriteria();
        criteria.andUserIdEqualTo(userId);
        List<RoleUserDO> roleUserDOList = roleUserDOMapper.selectByExample(roleUserDOExample);

        //2. 通过用户角色得到用户的资源权限
        List<String> pageList = new ArrayList<>(), requestList = new ArrayList<>(),
                roleIdList = new ArrayList<>(), resourceIdList = new ArrayList<>();
        for (RoleUserDO roleUserDO : roleUserDOList) {
            roleIdList.add(roleUserDO.getRoleId());
        }
        RoleResourceDOExample roleResourceDOExample = new RoleResourceDOExample();
        RoleResourceDOExample.Criteria roleResourceDOExampleCriteria = roleResourceDOExample.createCriteria();
        roleResourceDOExampleCriteria.andRoleIdIn(roleIdList);
        List<RoleResourceDO> roleResourceDOList = roleResourceDOMapper.selectByExample(roleResourceDOExample);

        //3. 通过用户的权限得到用户能够访问的具体资源
        ResourceDOExample resourceDOExample = new ResourceDOExample();
        ResourceDOExample.Criteria resourceDOExampleCriteria = resourceDOExample.createCriteria();
        for (RoleResourceDO roleResourceDO : roleResourceDOList) {
            resourceIdList.add(roleResourceDO.getResourceId());
        }
        resourceDOExampleCriteria.andIdIn(resourceIdList);
        List<ResourceDO> resourceDOList = resourceDOMapper.selectByExample(resourceDOExample);


        //4. 分离出来page和request
        for (ResourceDO resourceDO : resourceDOList) {
            if (StringUtils.isNotEmpty(resourceDO.getPage())) {
                pageList.add(resourceDO.getPage());
            }
            if (StringUtils.isNotEmpty(resourceDO.getRequest())) {
                List<String> singleRequestList = JSON.parseArray(resourceDO.getRequest(), String.class);
                requestList.addAll(singleRequestList);
            }
        }

        //5. 构造返回的map
        Map<String, List<String>> map = new HashMap<>();
        map.put("pageList", pageList);
        map.put("requestList", requestList);
        return map;

    }

    @Override
    public UserPasswordDO getUserPasswordDO(String userId) {
        UserPasswordDOExample example = new UserPasswordDOExample();
        UserPasswordDOExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(userId);
        List<UserPasswordDO> userPasswordDOList = userPasswordDOMapper.selectByExample(example);
        if (userPasswordDOList == null || userPasswordDOList.size() == 0) {
            return null;
        }
        return userPasswordDOList.get(0);

    }
}
